﻿using System;
using System.Collections.Generic;
using BizElements.Core;

namespace BizElements.BusinessLayer
{
    /// <summary>Builds journal table records using provided custom method.</summary>
    /// <typeparam name="TSourceEntity">Source table entity class.</typeparam>
    /// <typeparam name="TJournalEntity">Journal table entity class.</typeparam>
    public sealed class CustomJournalEntityBuilder<TSourceEntity, TJournalEntity> : IJournalEntityBuilder<TSourceEntity, TJournalEntity>
        where TSourceEntity : IEntity, new()
        where TJournalEntity : IEntity, new()
    {
        Delegates.Function<TJournalEntity, TSourceEntity> buildJournalEntityFromSource;
        Delegates.Function<IEntityCollection, IEnumerable<TSourceEntity>> buildJournalEntityCollectionFromSourceEntities;

        /// <summary>Initializaes a new instance of CustomJournalEntityBuilder class.</summary>
        /// <param name="buildJournalEntityFromSource">A delegate to a method that creates a journal record.</param>
        public CustomJournalEntityBuilder(Delegates.Function<TJournalEntity, TSourceEntity> buildJournalEntityFromSource)
        {
            this.buildJournalEntityFromSource = buildJournalEntityFromSource;
        }

        /// <summary>Initializaes a new instance of CustomJournalEntityBuilder class.</summary>
        /// <param name="buildJournalEntityFromSource">A delegate to a method that creates a journal record.</param>
        /// <param name="buildJournalEntityCollectionFromSourceEntities">Optional delegate to a method that creates journal entity collection. If null then buildJournalEntityFromSource method will be used for each source entity.</param>
        public CustomJournalEntityBuilder(Delegates.Function<TJournalEntity, TSourceEntity> buildJournalEntityFromSource,
            Delegates.Function<IEntityCollection, IEnumerable<TSourceEntity>> buildJournalEntityCollectionFromSourceEntities)
        {
            this.buildJournalEntityFromSource = buildJournalEntityFromSource;
            this.buildJournalEntityCollectionFromSourceEntities = buildJournalEntityCollectionFromSourceEntities;
        }

        /// <summary>Builds journal record for the specified source entity.</summary>
        /// <param name="entity">Entity whose properties will be journaled.</param>
        /// <returns>Journal table entity.</returns>
        public TJournalEntity BuildJournalEntity(TSourceEntity entity)
        {
            return this.buildJournalEntityFromSource(entity);
        }

        /// <summary>Builds journal record for the specified source entity.</summary>
        /// <param name="entities">Entities whose properties will be journaled.</param>
        /// <returns>Journal table entities.</returns>
        public IEntityCollection BuildJournalEntityCollection(IEnumerable<TSourceEntity> entities)
        {
            if (this.buildJournalEntityCollectionFromSourceEntities != null)
            {
                return this.buildJournalEntityCollectionFromSourceEntities(entities);
            }
            else
            {
                EntityCollection journalEntities = new EntityCollection(new TJournalEntity().Table);
                foreach (TSourceEntity sourceEntity in entities)
                    journalEntities.Add(this.buildJournalEntityFromSource(sourceEntity));

                return journalEntities;
            }
        }
    }
}
